use chrono::Timelike;
use serde::{Deserialize, Serialize};
use wither::{
    bson::{doc, oid::ObjectId, to_bson, DateTime, Document},
    Model,
};

use crate::AppResult;

use super::user::SimpleUserModel;

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum WatchRecordContent {
    #[serde(rename = "club")]
    Club { club_id: ObjectId },
    #[serde(rename = "article")]
    Article { article_id: ObjectId },
    #[serde(rename = "section")]
    Section { section_id: ObjectId },
    #[serde(rename = "unknown")]
    Unknown,
}

impl Default for WatchRecordContent {
    fn default() -> Self {
        Self::Unknown
    }
}

impl_try_into_bson!(WatchRecordContent);

/// ## 观看记录
/// 当用户观看社团或者文章时应该将其观看操作记录并统计下来
#[derive(Debug, Clone, Serialize, Deserialize, Model)]
pub struct WatchRecordModel {
    #[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
    pub id: Option<ObjectId>,
    pub target_user: SimpleUserModel,
    pub content: WatchRecordContent,
    pub created_at: DateTime,
}

impl Default for WatchRecordModel {
    fn default() -> Self {
        Self {
            id: None,
            target_user: Default::default(),
            content: Default::default(),
            created_at: DateTime::now(),
        }
    }
}

impl WatchRecordModel {
    #[inline]
    pub fn record_user_watch<U: Into<SimpleUserModel>, C: Into<WatchRecordContent>>(
        user: U,
        content: C,
    ) -> Self {
        Self {
            id: None,
            target_user: user.into(),
            content: content.into(),
            created_at: DateTime::now(),
        }
    }
    #[inline]
    pub fn document_from_instance_without_created_at(&self) -> AppResult<Document> {
        let mut document = self.document_from_instance()?;
        document.remove("created_at");
        Ok(document)
    }

    pub fn get_filter_document(&self) -> AppResult<Document> {
        let mut document = Document::new();
        document.insert("target_user.id", self.target_user.id);
        document.insert("content", to_bson(&self.content)?);
        let now = chrono::Utc::now();
        let time_limit = now
            .with_hour(23)
            .unwrap_or(now)
            .with_minute(59)
            .unwrap_or(now)
            .with_second(59)
            .unwrap_or(now);
        document.insert(
            "created_at",
            doc! {
                "$lte":DateTime::from_chrono(time_limit)
            },
        );
        Ok(document)
    }
}
